﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Jayden.Dll.Cards.Enums;
using System.Diagnostics;

namespace Jayden.Dll.Cards.Poker
{
	public class TexasHoldemHandRange : IComparable<TexasHoldemHandRange>, ICloneable
	{
		private TexasHoldemHandCategory m_Start;
		private TexasHoldemHandCategory m_End;

		public TexasHoldemHandRange(TexasHoldemHandCategory category) : this(category, null) { }
		public TexasHoldemHandRange(TexasHoldemHandCategory start, TexasHoldemHandCategory end)
		{
			if (start == null)
				throw new NullReferenceException();
			m_Start = start;
			if (end != null)
			{
				m_End = end;
				if (start.IsPair != end.IsPair || start.IsSuited != start.IsSuited)
					throw new Exception("Invalid range");
				if (!start.IsPair && start[0] != end[0])
					throw new Exception("Invalid range");
				if (start[1].CompareTo(end[1]) >= 0)
					throw new Exception("Invalid range");
			}
		}

		public bool IsRange { get { return m_End != null; } }
		public bool IsPair { get { return m_Start.IsPair; } }
		public bool IsSuited { get { return m_Start.IsSuited; } }

		public override string ToString()
		{
			if (IsRange)
			{
				if (IsPair && m_End[0] == CardRank.Ace)
					return m_Start.ToString() + "+";
				if (!IsPair && m_Start[0] - 1 == m_End[1])
					return m_Start.ToString() + "+";
				return string.Format("{0}-{1}", m_Start, m_End);
			}
			return m_Start.ToString();
		}

		public static TexasHoldemHandRange Parse(string range)
		{
			if (range.EndsWith("+"))
			{
				TexasHoldemHandCategory start = TexasHoldemHandCategory.Parse(range.Substring(0, range.Length - 1));
				TexasHoldemHandCategory end = null;
				if (start.IsPair)
					end = TexasHoldemHandCategory.Parse("AA");
				else
					end = new TexasHoldemHandCategory(start[0], start[0] - 1, start.IsSuited);
				return new TexasHoldemHandRange(start, end);
			}
			else if (range.Contains("-"))
			{
				string[] parts = range.Split('-');
				if(parts.Length != 2)
					throw new Exception("Invalid format");
				return new TexasHoldemHandRange(TexasHoldemHandCategory.Parse(parts[0]), TexasHoldemHandCategory.Parse(parts[1]));
			}
			else
				return new TexasHoldemHandRange(TexasHoldemHandCategory.Parse(range));
			throw new Exception("Invalid format");
		}

		public int Count
		{
			get
			{
				if (IsRange)
					return 1 + (m_End[1] - m_Start[1]);
				return 1;
			}
		}

		public bool Join(TexasHoldemHandRange range)
		{
			if (IsPair == range.IsPair && (IsPair || (m_Start[0] == range.m_Start[0] && IsSuited == range.IsSuited)))
			{
				if (Contains(range))
					return true;
				if (range.Contains(this))
				{
					m_Start = range.m_Start;
					m_End = range.m_End;
					return true;
				}
				if (!IsRange && !range.IsRange)
				{
					if (m_Start[1] == range.m_Start[1] + 1)
					{
						m_End = m_Start;
						m_Start = range.m_Start;
						return true;
					}
					else if (range.m_Start[1] == m_Start[1] + 1)
					{
						m_End = range.m_Start;
						return true;
					}
				}
				else if (!IsRange && range.IsRange)
				{
					if (m_Start[1] == range.m_End[1] + 1)
					{
						m_End = m_Start;
						m_Start = range.m_Start;
						return true;
					}
					else if (range.m_Start[1] == m_Start[1] + 1)
					{
						m_End = range.m_End;
						return true;
					}
				}
				else if (IsRange && !range.IsRange)
				{
					if (m_Start[1] == range.m_Start[1] + 1)
					{
						m_Start = range.m_Start;
						return true;
					}
					else if (range.m_Start[1] == m_End[1] + 1)
					{
						m_End = range.m_Start;
						return true;
					}
				}
				else if (IsRange && range.IsRange)
				{
					if (m_Start[1] <= range.m_End[1] + 1 && m_Start[1] > range.m_Start[1])
					{
						m_Start = range.m_Start;
						if (m_End[1] < range.m_End[1])
							m_End = range.m_End;
						return true;
					}
					else if (m_End[1] >= range.m_Start[1] && m_End[1] < range.m_End[1])
					{
					}
				}
			}
			return false;
		}

		// http://en.wikipedia.org/wiki/Texas_hold_'em_starting_hands
		public double Percentage
		{
			get
			{
				//long ways = (52 * 51) / 2;
				double basePct = 0.0;
				if (IsPair) // 1 / 221
					basePct = (1.0 / 221.0);
				else if (IsSuited) // 2 / 663
					basePct = (2.0 / 663.0);
				else //offsuit // 2 / 221
					basePct = (2.0 / 221.0);
				return basePct * Count;
			}
		}

		public bool Contains(TexasHoldemHandRange range)
		{
			if (IsPair == range.IsPair && IsSuited == range.IsSuited)
			{
				if (!IsPair && m_Start[0] != range.m_Start[0])
					return false;
				if (!IsRange && !range.IsRange && m_Start[1].Equals(range.m_Start[1]))
					return true;
				if (IsRange && range.IsRange && m_Start[1] <= range.m_Start[1] && m_End[1] >= range.m_End[1])
					return true;
				if (IsRange && !range.IsRange && m_Start[1] <= range.m_Start[1] && m_End[1] >= range.m_Start[1])
					return true;
				if (!IsRange && range.IsRange)
					return false;
			}
			return false;
		}

		public int CompareTo(TexasHoldemHandRange other)
		{
			int compare = 0;
			if (IsRange && other.IsRange)
				compare = m_End.CompareTo(other.m_End);
			else if (IsRange && !other.IsRange)
				compare = m_End.CompareTo(other.m_Start);
			else if (!IsRange && other.IsRange)
				compare = m_Start.CompareTo(other.m_End);
			else
				compare = m_Start.CompareTo(other.m_Start);
			if (compare == 0)
				compare = IsRange.CompareTo(other.IsRange);
			return -compare;
		}

		public object Clone()
		{
			return new TexasHoldemHandRange(m_Start, m_End);
		}
	}

	[DebuggerDisplay("{ToString()}")]
	public class TexasHoldemHandRangeList : List<TexasHoldemHandRange>
	{
		public double Percentage
		{
			get
			{
				double percentage = 0.0;
				foreach (TexasHoldemHandRange range in this)
					percentage += range.Percentage;
				return percentage;
			}
		}

		public static TexasHoldemHandRangeList Parse(string line)
		{
			string[] parts = line.Split(',');
			TexasHoldemHandRangeList result = new TexasHoldemHandRangeList();
			foreach (string part in parts)
				if(!string.IsNullOrWhiteSpace(part))
					result.AddOrJoin(TexasHoldemHandRange.Parse(part.Trim()));
			return result;
		}

		public void AddOrJoin(TexasHoldemHandRange item)
		{
			foreach (TexasHoldemHandRange range in this)
				if (range.Join(item))
					return;
			Add(item);
			Sort();
		}

		public override string ToString()
		{
			return string.Join(", ", this);
		}
	}

	public class TexasHoldemHandRangeModel : List<TexasHoldemHandRangeList>
	{
		public double Percentage
		{
			get
			{
				double percentage = 0.0;
				foreach (TexasHoldemHandRangeList range in this)
					percentage += range.Percentage;
				return percentage;
			}
		}

		public TexasHoldemHandRangeList GetHandRange(double percentage)
		{
			TexasHoldemHandRangeList list = new TexasHoldemHandRangeList();
			for (int c = 0; c < Count; c++)
			{
				foreach (TexasHoldemHandRange range in this[c])
					list.AddOrJoin(range.Clone() as TexasHoldemHandRange);
				if (list.Percentage >= percentage)
					return list;
			}
			return list;
		}
	}
}
